package my.edu.handler;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.ValidationException;
import jakarta.validation.metadata.ConstraintDescriptor;
import lombok.extern.slf4j.Slf4j;
import my.edu.common.domain.Response;
import my.edu.common.domain.purchase.ProductWithHighPrice;
import my.edu.common.enumeration.OrderType;
import my.edu.common.exception.*;
import my.edu.common.exception.Order.AuditException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.ai.retry.TransientAiException;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.servlet.resource.NoResourceFoundException;


import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    @ResponseBody
    //@ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(Exception.class)
    public Response handleException(Exception e) {
        log.warn("未知异常", e);
        return Response.error("未知异常", e.getMessage());
    }

    @ResponseBody
    @ExceptionHandler(UserLoginException.class)
    public Response handleUserLoginException(Exception e) {
        log.warn("登录异常", e);
        return Response.error(e.getMessage());
    }

    @ResponseBody
    @ExceptionHandler(AdminException.class)
    public Response handleAdminException(Exception e) {
        log.warn("管理员异常", e);
        return Response.error(e.getMessage());
    }

    @ResponseBody
    @ExceptionHandler(ResourceAccessException.class)
    public Response handleResourceAccessException(Exception e) {
        log.warn("ai错误", e);
        return Response.warn("未能连接到服务器请稍后重试或者联系管理员！");
    }

    @ResponseBody
    @ExceptionHandler(CustomerException.class)
    public Response handleCustomerException(CustomerException e) {
        log.warn("客户管理异常", e);
        return Response.error(e.getMessage());
    }


    @ResponseBody
    @ExceptionHandler(RedisConnectionFailureException.class)
    public Response handleException(RedisConnectionFailureException e) {
        log.warn("检查redis", e);
        return Response.error("后台异常", "错误代码：R");
    }

    @ResponseBody
    @ExceptionHandler(NoResourceFoundException.class)
    public Response handleException(NoResourceFoundException e) {
        log.warn("访问未知资源", e);
        return Response.error("异常", "请访问系统资源！");
    }

    @ResponseBody
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public Response handleException(MissingServletRequestParameterException e) {
        log.warn("未携带完整参数", e);
        return Response.error("请检查参数传递是否正确！" );
    }

    @ResponseBody
    @ExceptionHandler(HttpMessageConversionException.class)
    public Response handleHttpMessageConversionException(HttpMessageConversionException e) {
        log.info("参数转换失败：{}", e.getMessage());
        return Response.error("检查参数！");
    }

    @ResponseBody
    @ExceptionHandler(UnauthorizedException.class)
    public Response handleUnauthorizedException(UnauthorizedException e) {
        log.info("权限校验失败：{}", e.getMessage());
        return Response.error("用户无权限");
    }

    @ResponseBody
    @ExceptionHandler(BillsException.class)
    public Response handleUnauthorizedException(BillsException e) {
        log.info("单据异常：{}", e.getMessage());
        return Response.error(e.getMessage());
    }

    @ResponseBody
    @ExceptionHandler(AuditException.class)
    public Response handleUnauthorizedException(AuditException e) {
        log.info("审核异常：{}", e.getMessage());
        return Response.error(e.getMessage());
    }

    //实体类校验出错
    @ExceptionHandler(value = {MethodArgumentNotValidException.class})
    //@ExceptionHandler(BindException.class)
    @ResponseBody
    public Response methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e, HttpServletRequest request) {

        // Map<String, String> result = new HashMap<>();
        List<String> result = new ArrayList<>();
        BindingResult bindingResult = e.getBindingResult();
        log.error("请求[ {} ] {} 的参数校验发生错误", request.getMethod(), request.getRequestURL());
        for (ObjectError objectError : bindingResult.getAllErrors()) {
            FieldError fieldError = (FieldError) objectError;
            log.error("参数 {} = {} 校验错误：{}", fieldError.getField(), fieldError.getRejectedValue(), fieldError.getDefaultMessage());
            //  result.put(fieldError.getField(), fieldError.getDefaultMessage());
            result.add(fieldError.getDefaultMessage());
        }
        return Response.error(String.join(",",result));

    }

    //接口的单一参数校验出错
    @ExceptionHandler(value = {ConstraintViolationException.class})
    @ResponseBody
    public Response ConstraintViolationExceptionHandler(ConstraintViolationException e, HttpServletRequest request) {

        List<String> result = new ArrayList<>();
        Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
        log.error("请求[ {} ] {} 的参数校验发生错误", request.getMethod(), request.getRequestURL());
        for (ConstraintViolation<?> constraintViolation : constraintViolations) {
            result.add(constraintViolation.getMessageTemplate());
        }
        return Response.error(String.join(",",result));
    }

    @ResponseBody
    @ExceptionHandler(OverHighPriceException.class)
    public Response handleOverHighPriceException(OverHighPriceException e) {
        ProductWithHighPrice productWithHighPriceList = e.getProductWithHighPriceList();
        if (productWithHighPriceList.getOrderType() == OrderType.PURCHASE_PRICE) {
            log.info("采购价格过高：{}", e.getMessage());
            return Response.warn("采购价格过高", productWithHighPriceList.getDetail());
        } else if (productWithHighPriceList.getOrderType() == OrderType.SALE_PRICE) {
            log.info("销售价格过低：{}", e.getMessage());
            return Response.warn("销售价格过低", productWithHighPriceList.getDetail());
        }
        return Response.warn("检查价格", productWithHighPriceList.getDetail());
    }

}
